import os
import time
import subprocess
from datetime import datetime
import logging
from configparser import ConfigParser

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('live_capture.log'),
        logging.StreamHandler()
    ]
)


class LiveStreamCapture:
    def __init__(self, config_path='config.ini'):
        """初始化直播流捕获器"""
        # 手动指定FFmpeg可执行文件路径（根据你的实际安装路径修改）
        self.ffmpeg_path = r'E:\ffmpeg\bin\ffmpeg.exe'  # 关键修改：替换为你的ffmpeg.exe路径

        self.config = self.load_config(config_path)
        self.live_url = self.clean_value(self.config['DEFAULT']['live_url'])
        self.output_dir = self.clean_value(self.config['DEFAULT']['output_dir'])

        self.frame_interval = int(self.clean_value(self.config['CAPTURE']['frame_interval']))
        self.audio_interval = int(self.clean_value(self.config['CAPTURE']['audio_interval']))
        self.audio_duration = int(self.clean_value(self.config['CAPTURE']['audio_duration']))

        # 创建输出目录
        self.frame_dir = os.path.join(self.output_dir, 'frames')
        self.audio_dir = os.path.join(self.output_dir, 'audio')
        os.makedirs(self.frame_dir, exist_ok=True)
        os.makedirs(self.audio_dir, exist_ok=True)

        self.last_audio_time = 0
        self.running = True

    def clean_value(self, value):
        """清理配置值中的注释和空白字符"""
        if '#' in value:
            value = value.split('#', 1)[0]
        return value.strip()

    def load_config(self, config_path):
        """加载配置文件（指定UTF-8编码）"""
        if not os.path.exists(config_path):
            self.create_default_config(config_path)

        config = ConfigParser()
        with open(config_path, 'r', encoding='utf-8') as f:
            config.read_file(f)
        return config

    def create_default_config(self, config_path):
        """创建默认配置文件"""
        config = ConfigParser()
        config['DEFAULT'] = {
            'live_url': 'https://d1--ov-gotcha207.bilivideo.com/live-bvc/467502/live_552254379_65281731_bluray/index.m3u8?expires=1757482267&len=0&oi=1823802495&pt=web&qn=10000&trid=10075e77520fdeda7bbd5e5b81c1db68c0ff&bmt=1&sigparams=cdn,expires,len,oi,pt,qn,trid,bmt&cdn=ov-gotcha207&sign=9b245c9423100072c82a62dd828d5fc0&site=5a5d3f5c446549a680628cfd621c9bd1&free_type=0&mid=397870019&sche=ban&bvchls=1&trace=0&isp=other&rg=other&pv=other&score=1&long_ab_id=45&deploy_env=prod&origin_bitrate=2330&pp=rtmp&sk=fc53131b8465f6aa53a11413bcfe3ef1&suffix=bluray&expected_qn=10000&codec=0&flvsk=25ed97f12ce8b5c35ad89e32d6451a68&source=puv3_onetier&strategy_ids=11,11&info_source=cache&media_type=0&long_ab_flag_value=test&hot_cdn=909705&strategy_version=latest&strategy_types=0,1&hdr_type=0&sl=3&p2p_type=-1&long_ab_flag=live_default_longitudinal&ld=xs&strategy_type=0&strategy_id=11&vd=bc&src=puv3&order=1',
            'output_dir': 'live_captures'
        }
        config['CAPTURE'] = {
            'frame_interval': '10',
            'audio_interval': '20',
            'audio_duration': '5'
        }

        with open(config_path, 'w', encoding='utf-8') as f:
            config.write(f)
        logging.info(f"已创建默认配置文件: {config_path}")

    def capture_frame(self):
        """捕获单帧视频并保存"""
        try:
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            frame_path = os.path.join(self.frame_dir, f"frame_{timestamp}.jpg")

            # 关键修改：使用self.ffmpeg_path替代'ffmpeg'
            cmd = [
                self.ffmpeg_path, '-i', self.live_url,
                '-ss', '0', '-vframes', '1',
                '-q:v', '2', '-y', '-loglevel', 'error',
                frame_path
            ]

            result = subprocess.run(cmd, capture_output=True, text=True)
            if result.returncode == 0:
                logging.info(f"已保存视频帧: {frame_path}")
                return frame_path
            else:
                logging.error(f"捕获视频帧失败: {result.stderr}")
                return None

        except Exception as e:
            logging.error(f"捕获视频帧时发生错误: {str(e)}")
            return None

    def capture_audio(self):
        """捕获音频片段并保存"""
        try:
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            audio_path = os.path.join(self.audio_dir, f"audio_{timestamp}.mp3")

            # 关键修改：使用self.ffmpeg_path替代'ffmpeg'
            cmd = [
                self.ffmpeg_path, '-i', self.live_url,
                '-ss', '0', '-t', str(self.audio_duration),
                '-c:a', 'libmp3lame', '-b:a', '128k',
                '-y', '-loglevel', 'error',
                audio_path
            ]

            result = subprocess.run(cmd, capture_output=True, text=True)
            if result.returncode == 0:
                logging.info(f"已保存音频片段: {audio_path}")
                return audio_path
            else:
                logging.error(f"捕获音频失败: {result.stderr}")
                return None

        except Exception as e:
            logging.error(f"捕获音频时发生错误: {str(e)}")
            return None

    def start(self):
        """开始定时捕获"""
        # 验证FFmpeg路径是否有效
        if not os.path.exists(self.ffmpeg_path):
            logging.error(f"FFmpeg未找到！请检查路径: {self.ffmpeg_path}")
            return

        logging.info("开始直播流定时捕获...")
        logging.info(f"直播地址: {self.live_url}")
        logging.info(f"视频帧间隔: {self.frame_interval}秒")
        logging.info(f"音频间隔: {self.audio_interval}秒，每次时长: {self.audio_duration}秒")

        try:
            while self.running:
                current_time = time.time()
                self.capture_frame()

                if current_time - self.last_audio_time >= self.audio_interval:
                    self.capture_audio()
                    self.last_audio_time = current_time

                time.sleep(self.frame_interval)

        except KeyboardInterrupt:
            logging.info("用户中断，停止捕获")
        except Exception as e:
            logging.error(f"捕获过程发生错误: {str(e)}")
        finally:
            self.stop()

    def stop(self):
        """停止捕获"""
        self.running = False
        logging.info("已停止直播流捕获")


if __name__ == "__main__":
    capture = LiveStreamCapture()
    capture.start()
